package com.smart.cosstarter.config;

import com.cue.es.oss.annotation.*;
import com.smart.cosstarter.annotation.*;
import com.smart.cosstarter.constance.DefaultBuckets;
import com.smart.cosstarter.exception.NoBucketExeception;
import com.smart.cosstarter.exception.NoFileException;
import com.smart.cosstarter.exception.NoKeyException;
import com.smart.cosstarter.model.DownObjectRequest;
import com.smart.cosstarter.model.DownloadObject;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: jj
 * @Date: 2019/8/23 16:44
 * @Version 1.0
 */
@Component
@ConditionalOnBean({COSObjectManager.class,})
public class ServiceInjectProcessor implements BeanPostProcessor {

	@Autowired
	private COSObjectManager cosObjectManager;

	/**
	 * bean初始化之前要调用的方法，这里直接返回
	 *
	 * @param bean
	 * @param beanName
	 * @return
	 * @throws BeansException
	 */
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * bean初始化之后要调用的方法，这里判断如果有自定义注解@MyAnnotation时，做进一步处理
	 *
	 * @param bean
	 * @param beanName
	 * @return
	 * @throws BeansException
	 */
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		Class<?> targeClass = bean.getClass();
		UseCOS useBucket = AnnotationUtils.findAnnotation(targeClass, UseCOS.class);

		if (useBucket != null) {
			List<Field> fieldList = new ArrayList<>();
			while (targeClass != null){
				fieldList.addAll(Arrays.asList(targeClass .getDeclaredFields()));
				targeClass = targeClass.getSuperclass();
			}
			for (Field declaredField : fieldList) {
				Download download = AnnotationUtils.findAnnotation(declaredField, Download.class);
				Upload upload = AnnotationUtils.findAnnotation(declaredField, Upload.class);
				DownloadRemoveSrc downloadRemoveSrc = AnnotationUtils.findAnnotation(declaredField, DownloadRemoveSrc.class);
				UploadRemoveSrc uploadRemoveSrc = AnnotationUtils.findAnnotation(declaredField, UploadRemoveSrc.class);
				String bucketName = DefaultBuckets.bucket;
				if (useBucket.bucketName() != null && !"".equals(useBucket.bucketName())) {
					bucketName = useBucket.bucketName();
				}
				if (download != null) {
					bucketName = "".equals(download.bucketName()) ? bucketName : download.bucketName();
					if ("".equals(bucketName)) {
						throw new NoBucketExeception();
					}
					if ("".equals(download.key())) {
						throw new NoKeyException();
					}
					if (declaredField.getGenericType().getTypeName().equals(File.class.getTypeName())) {
						try {
							File file = (File) declaredField.get(bean);
							if (file == null) {
								file = new File(download.key());
							}
							if (!file.exists()) {
								file.createNewFile();
							}
							if (download.asyn()) {
								cosObjectManager.asynchDownload(bucketName, download.key(), file);
							} else {
								cosObjectManager.synchDownload(bucketName, download.key(), file);
							}
							hanldMyAnnotation(declaredField, bean, file);
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InterruptedException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
					} else if (declaredField.getGenericType().getTypeName().equals(DownloadObject.class.getTypeName())) {
						String dirs = "/temp";
						if (DefaultBuckets.baseDir != null && !"".equals(DefaultBuckets.baseDir)) {
							dirs = DefaultBuckets.baseDir;
						}
						DownObjectRequest request = new DownObjectRequest(bucketName, download.key(), dirs);
						File dir = new File(request.getToPath());
						// 判断文件目录是否存在
						if (!dir.exists() && dir.isDirectory()) {
							dir.mkdirs();
						}
						File file = new File(request.getToPath(), request.getFileName());
						if (!file.exists()) {
							try {
								file.createNewFile();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
						try {
							cosObjectManager.synchDownload(request, file);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						DownloadObjectInstance instance = (DownloadObjectInstance) DownloadObjectInstance.getInstance(file, bucketName, download.key());
						file.deleteOnExit();
						try {
							hanldMyAnnotation(declaredField, bean, instance);
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					}
				}
				if (downloadRemoveSrc != null) {
					bucketName = "".equals(downloadRemoveSrc.bucketName()) ? bucketName : downloadRemoveSrc.bucketName();
					if ("".equals(bucketName)) {
						throw new NoBucketExeception();
					}
					if ("".equals(downloadRemoveSrc.key())) {
						throw new NoKeyException();
					}
					if (declaredField.getGenericType().getTypeName().equals(File.class.getTypeName())) {
						try {
							File file = (File) declaredField.get(bean);
							if (file == null) {
								file = new File(downloadRemoveSrc.key());
							}
							if (!file.exists()) {
								file.createNewFile();
							}
							if (downloadRemoveSrc.asyn()) {
								cosObjectManager.asynchDownload(bucketName, downloadRemoveSrc.key(), file);
								cosObjectManager.deleteObject(bucketName, downloadRemoveSrc.key());
							} else {
								cosObjectManager.synchDownload(bucketName, downloadRemoveSrc.key(), file);
								cosObjectManager.deleteObject(bucketName, downloadRemoveSrc.key());
							}
							hanldMyAnnotation(declaredField, bean, file);
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InterruptedException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
					} else if (declaredField.getGenericType().getTypeName().equals(DownloadObject.class.getTypeName())) {
						String dirs = "/temp";
						if (DefaultBuckets.baseDir != null && !"".equals(DefaultBuckets.baseDir)) {
							dirs = DefaultBuckets.baseDir;
						}
						DownObjectRequest request = new DownObjectRequest(bucketName, downloadRemoveSrc.key(), dirs);
						File dir = new File(request.getToPath());
						// 判断文件目录是否存在
						if (!dir.exists() && dir.isDirectory()) {
							dir.mkdirs();
						}
						File file = new File(request.getToPath(), request.getFileName());
						if (!file.exists()) {
							try {
								file.createNewFile();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
						try {
							cosObjectManager.synchDownload(request, file);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						DownloadObjectInstance instance = (DownloadObjectInstance) DownloadObjectInstance.getInstance(file, bucketName, downloadRemoveSrc.key());
						file.deleteOnExit();
						cosObjectManager.deleteObject(bucketName, downloadRemoveSrc.key());
						try {
							hanldMyAnnotation(declaredField, bean, instance);
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					}
				}
				if (upload != null) {
					bucketName = "".equals(upload.bucketName()) ? bucketName : upload.bucketName();
					if ("".equals(bucketName)) {
						throw new NoBucketExeception();
					}
					if ("".equals(upload.key())) {
						throw new NoKeyException();
					}
					if (declaredField.getGenericType().getTypeName().equals(File.class.getTypeName())) {
						try {
							File file = (File) declaredField.get(bean);
							String key = file.getName();
							if (!"".equals(upload.key())) {
								if (upload.key().endsWith("/")) {
									key = upload.key() + key;
								} else {
									key = upload.key();
								}
							}
							if (file == null) {
								throw new NoFileException();
							}
							if (!file.exists()) {
								throw new NoFileException();
							}
							if (upload.asyn()) {
								cosObjectManager.asynchUpload(bucketName, key, file);
							} else {
								cosObjectManager.synchUpload(bucketName, key, file);
							}
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				if (uploadRemoveSrc != null) {
					bucketName = "".equals(uploadRemoveSrc.bucketName()) ? bucketName : uploadRemoveSrc.bucketName();
					if ("".equals(bucketName)) {
						throw new NoBucketExeception();
					}
					if ("".equals(uploadRemoveSrc.key())) {
						throw new NoKeyException();
					}
					if (declaredField.getGenericType().getTypeName().equals(File.class.getTypeName())) {
						try {
							File file = (File) declaredField.get(bean);
							String key = file.getName();
							if (!"".equals(uploadRemoveSrc.key())) {
								if (uploadRemoveSrc.key().endsWith("/")) {
									key = uploadRemoveSrc.key() + key;
								} else {
									key = uploadRemoveSrc.key();
								}
							}
							if (file == null) {
								throw new NoFileException();
							}
							if (!file.exists()) {
								throw new NoFileException();
							}
							if (uploadRemoveSrc.asyn()) {
								cosObjectManager.asynchUpload(bucketName, key, file);
								file.delete();
							} else {
								cosObjectManager.synchUpload(bucketName, key, file);
								file.delete();
							}
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}

		return bean;
	}

	private void hanldMyAnnotation(Field field, Object bean, Object value) throws IllegalAccessException {
		//设置该域可设置修改
		field.setAccessible(true);
		//将找到的实例赋值给属性域
		field.set(bean, value);
	}

}
